package me.springboot.mybatis.zhcs.socket;

import me.springboot.mybatis.common.utils.JSONUtil;
import me.springboot.mybatis.common.utils.StringUtil;
import me.springboot.mybatis.dao.*;
import me.springboot.mybatis.enmu.DeviceTypeEnum;
import me.springboot.mybatis.model.*;
import me.springboot.mybatis.service.ConfigService;
import me.springboot.mybatis.service.DeviceService;
import me.springboot.mybatis.zhcs.utils.ByteUtils;
import me.springboot.mybatis.zhcs.utils.DateUtils;
import me.springboot.mybatis.zhcs.utils.IDGenerator;
import me.springboot.mybatis.zhcs.utils.SpringUtils;
import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.springframework.context.ApplicationContext;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 自定义解码器(确保能读取到完整的包)
 *
 * @author Shinobi
 */
public class ByteArrayDecoder extends CumulativeProtocolDecoder {
    private ApplicationContext applicationContent = SpringUtils.getApplicationContext();
    private CoverMapper coverMapper = applicationContent.getBean(CoverMapper.class);
    private TrashMapper trashMapper = applicationContent.getBean(TrashMapper.class);
    private TrashDataMapper trashDataMapper = applicationContent.getBean(TrashDataMapper.class);
    private ConfigService configService = applicationContent.getBean(ConfigService.class);
    private DeviceService deviceService = applicationContent.getBean(DeviceService.class);
    private DeviceMapper deviceMapper = applicationContent.getBean(DeviceMapper.class);
    private ConfigMapper configMapper = applicationContent.getBean(ConfigMapper.class);

    /*private CoverMapper coverMapper = null;
    private TrashMapper trashMapper = null;
    private TrashDataMapper trashDataMapper = null;*/
    //    private CoverDao coverDao = applicationContent.getBean(CoverDao.class);
//    private TrashDataDao trashDataDao = applicationContent.getBean(TrashDataDao.class);
//    private TrashDao trashDao = applicationContent.getBean(TrashDao.class);
    private static final Logger logger = Logger.getLogger(ByteArrayDecoder.class);

    @Override
    protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
        byte[] bytes;

        if (!in.isAutoExpand()) {
            int pakelength = in.remaining();    //消息长度
            logger.info("长度：" + pakelength);
            bytes = new byte[2];
            in.get(bytes);
            //判断数据包头是否为固定0x3F - 0x3F
            logger.info("包头：" + ByteUtils.BinaryToHexString(bytes));
            if (ByteUtils.BinaryToHexString(bytes).equals("3F3F")) {
                bytes = new byte[2];
                in.get(bytes);
                //帧长度
                int frameLength = ByteUtils.byte2Uint16(bytes);
                bytes = new byte[2];
                in.get(bytes);
                //指令类型
                int command_type = ByteUtils.byte2Uint16(bytes);
                logger.info(frameLength + "  " + command_type + "   length:" + in.remaining());
                //标记 跳过数据部分
                in.mark();
                bytes = new byte[frameLength - 2];
                in.get(bytes);
                logger.info("length:" + in.remaining());
                //帧校验
                bytes = new byte[2];
                in.get(bytes);
                int framecheck = ByteUtils.byte2Uint16(bytes);
                logger.info("帧校验:" + framecheck);
                bytes = new byte[2];
                in.get(bytes);
                if (ByteUtils.BinaryToHexString(bytes).equals("4040")) {
                    //验证完毕 重置回复到mark位置进行数据解析
                    in.reset();
                    decoding(in);
                }
            }
        }
        //处理成功，让父类进行接收下个包*/
        return false;
    }


    /**
     * 解析
     *
     * @param in
     */
    private Map<String, Object> decoding(IoBuffer in) {
        byte[] bytes;
        //数据包第一位 设备类型
        bytes = new byte[1];
        in.get(bytes);
        int command_type = Integer.parseInt(ByteUtils.BinaryToHexString(bytes));
        //环境参数上传:0x0001
        logger.info("command_type=" + command_type);
        if (command_type == 1) {
            toCover(in);
        } else if (command_type == 2) {
            toTrash(in);
        }
        return null;
    }

    private void toTrash(IoBuffer in) {
        byte[] bytes;
        Trash trash = new Trash();
        String tid = IDGenerator.getStrID();
        trash.setId(tid);
        trash.setDevicetype(DeviceTypeEnum.LaJi.getCode());
        //程序版本号
        bytes = new byte[2];
        in.get(bytes);
        trash.setVersion(ByteUtils.BinaryToHexString(bytes));
        //设备号
        String sim = "";
        String imei = "";
        String serialnumber = "";
        try {
            //（SIM 卡号（20）
            bytes = new byte[20];
            in.get(bytes);
            sim = new String(bytes, "utf-8");
            //IMEI 号 （15）
            bytes = new byte[15];
            in.get(bytes);
            imei = new String(bytes, "utf-8");
            //设备序列号（32）
            bytes = new byte[32];
            in.get(bytes);
            serialnumber = new String(bytes, "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        trash.setSim(sim);
        trash.setImei(imei);
        trash.setDevicenum(serialnumber);
        //设备状态
        bytes = new byte[1];
        in.get(bytes);
        byte[] b = new byte[]{bytes[0], 0x00};
        int status = ByteUtils.byte2Uint16(b);
        if (status == 85) {
            trash.setDevicestate(1);
        } else if (status == 179) {
            trash.setDevicestate(2);
        } else {
            trash.setDevicestate(3);
        }
        //保存一份原始数据
        String originDeviceStatus = ByteUtils.BinaryToHexString(bytes);
        trash.setOriginDeviceStatus(originDeviceStatus);

//        trash.setDevicestate(ByteUtils.byte2Uint16(b));
        //报告类型
        bytes = new byte[1];
        in.get(bytes);
        b = new byte[]{bytes[0], 0x00};
        trash.setReporttype(ByteUtils.byte2Uint16(b));
        //数据包数
        bytes = new byte[2];
        in.get(bytes);
        int packageCount = ByteUtils.byte2Uint16(bytes);
        TrashData trashData = null;
        for (int i = 0; i < packageCount; i++) {
            trashData = new TrashData();
            trashData.setId(IDGenerator.getStrID());
            trashData.setTid(tid);
            //时间（年月日时分秒）年2000+X
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int yyyy = 2000 + ByteUtils.byte2Uint16(b);
            //月
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int mm = ByteUtils.byte2Uint16(b);
            //日
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int dd = ByteUtils.byte2Uint16(b);
            //时
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int HH = ByteUtils.byte2Uint16(b);
            //分
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int MM = ByteUtils.byte2Uint16(b);
            //秒
            bytes = new byte[1];
            in.get(bytes);
            b = new byte[]{bytes[0], 0x00};
            int SS = ByteUtils.byte2Uint16(b);
            trashData.setDatatime(DateUtils.parseDateTimeByString(yyyy + "-" + mm + "-" + dd + " " + HH + ":" + MM + ":" + SS).getTime());
            //温度
            bytes = new byte[2];
            in.get(bytes);
            trashData.setDatatemper(ByteUtils.byte2Uint16(bytes) + "");
            //垃圾实际高度（单位 mm）
            bytes = new byte[2];
            in.get(bytes);
            trashData.setHeight(ByteUtils.byte2Uint16(bytes) + "");
            //添加数据库
//            trashDataDao.save(trashData);
            trashDataMapper.insert(trashData);
        }
        //垃圾桶高度（单位 mm）
        bytes = new byte[2];
        in.get(bytes);
        trash.setBinheight(ByteUtils.byte2Uint16(bytes) + "");
        //首次上报水线阈值（单位 mm）
        bytes = new byte[2];
        in.get(bytes);
        trash.setFirstwaterlinethreshold(ByteUtils.byte2Uint16(bytes) + "");
        //第二次上报水线阈值（单位 mm)
        bytes = new byte[2];
        in.get(bytes);
        trash.setSecondwaterlinethreshold(ByteUtils.byte2Uint16(bytes) + "");
        //已清理阈值（单位 mm）
        bytes = new byte[2];
        in.get(bytes);
        trash.setClearedthreshold(ByteUtils.byte2Uint16(bytes) + "");
        //传输模式
        bytes = new byte[1];
        in.get(bytes);
        b = new byte[]{bytes[0], 0x00};
        trash.setMode(ByteUtils.byte2Uint16(b));
        //温度超限阈值（摄氏度℃*100）
        bytes = new byte[2];
        in.get(bytes);
        trash.setUppertemperature(ByteUtils.byte2Uint16(bytes) + "");
        //电池电量（电压 V*100）
        bytes = new byte[2];
        in.get(bytes);
        trash.setBatterylevel(ByteUtils.byte2Uint16(bytes));
        //电量（%）
        bytes = new byte[1];
        in.get(bytes);
        b = new byte[]{bytes[0], 0x00};
        trash.setElectricity(ByteUtils.byte2Uint16(b) + "");
        //相对湿度（%RH）预留
        bytes = new byte[2];
        in.get(bytes);
        trash.setHumidity(ByteUtils.byte2Uint16(bytes));
        //盖子/箱体角度（°）
        bytes = new byte[2];
        in.get(bytes);
        trash.setAngle_1(ByteUtils.byte2Uint16(bytes));
        //盖子/箱体角度（′）
        bytes = new byte[2];
        in.get(bytes);
        trash.setAngle_2(ByteUtils.byte2Uint16(bytes));
        //经度（度分分格式*10000）预留
        bytes = new byte[4];
        in.get(bytes);
        trash.setLongitude(ByteUtils.byte2int(bytes));
        //纬度（度分分格式*10000）预留
        bytes = new byte[4];
        in.get(bytes);
        trash.setLatitude(ByteUtils.byte2int(bytes));
        //预留1
        bytes = new byte[2];
        in.get(bytes);
        trash.setStr1(ByteUtils.BinaryToHexString(bytes));
        //预留2
        bytes = new byte[2];
        in.get(bytes);
        trash.setStr2(ByteUtils.BinaryToHexString(bytes));
        //预留3
        bytes = new byte[4];
        in.get(bytes);
        trash.setStr3(ByteUtils.BinaryToHexString(bytes));
        trash.setAddtime(new Date().getTime());
//        trashDao.save(trash);
        logger.info("trash=" + JSONUtil.beanToJson(trash));
        int dataStatus = updateTrash(trash, trashData);
        logger.info("dataStatus:" + dataStatus);
        trash.setDataStatus(dataStatus);
        trashMapper.insert(trash);
    }

    private int updateTrash(Trash trash, TrashData trashData) {
        Device queryDevice = new Device();
        queryDevice.setEquipmentNum(trash.getDevicenum());
        List<Device> devices = deviceMapper.selectModel(queryDevice);
        int dataStatus = 1;
        if (null != devices) {
            Device device = devices.get(0);
            trash.setLongitude(device.getLongitude());
            trash.setLatitude(device.getLatitude());
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("devicetype", DeviceTypeEnum.LaJi.getCode());
            paramMap.put("kehu_userid", device.getKehuUserid());
            List<Config> configs = configMapper.selectByMap(paramMap);
            device.setDeviceStatus(Integer.valueOf(trash.getDevicestate()));
            device.setDevicetype(Integer.valueOf(DeviceTypeEnum.LaJi.getCode()));
            for (Config config : configs) {
                if (config.getName().equals("lajiliang") && StringUtil.isNotBlank(config.getValue())) {
                    if (Integer.valueOf(trashData.getHeight()) > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                } else if (config.getName().equals("wendu") && StringUtil.isNotBlank(config.getValue())) {
                    if (Integer.valueOf(trashData.getDatatemper()) > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                } /*else if (config.getName().equals("clearedthreshold") && StringUtil.isNotBlank(config.getValue())) {
                    if (Integer.valueOf(trash.getClearedthreshold()) > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                }*/ else if (config.getName().equals("voltage") && StringUtil.isNotBlank(config.getValue())) {
                    if (trash.getBatterylevel() > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                }
            }
            device.setDataStatus(dataStatus);
            deviceService.update(device);
        }
        return dataStatus;
    }

    /**
     * 井盖数据包解析
     *
     * @param in
     */
    private void toCover(IoBuffer in) {
        byte[] bytes;
        Cover cover = new Cover();
        cover.setId(IDGenerator.getStrID());
        cover.setDeviceType(DeviceTypeEnum.JingGai.getCode());
        //程序版本号
        bytes = new byte[2];
        in.get(bytes);
        cover.setVersion(ByteUtils.BinaryToHexString(bytes));
        //设备号
        bytes = new byte[16];
        in.get(bytes);
        cover.setDeviceid(ByteUtils.BinaryToHexString(bytes));
        //设备状态
        bytes = new byte[1];
        in.get(bytes);
        String status = ByteUtils.BinaryToHexString(bytes);
        if (status.equals("1")) {
            cover.setDeviceState("1");
        } else if (status.equals("4")) {
            cover.setDeviceState("3");
        } else {
            cover.setDeviceState("2");
        }
        //保存一份原始数据
        cover.setOriginDeviceStatus(status);
//        cover.setDeviceState(ByteUtils.BinaryToHexString(bytes));
        //通信传输模式
        bytes = new byte[1];
        in.get(bytes);
        cover.setMode(ByteUtils.BinaryToHexString(bytes));
        //温度（摄氏度℃*100）
        bytes = new byte[2];
        in.get(bytes);
        cover.setTemperature(ByteUtils.byte2Uint16(bytes));
        //液面高度
        bytes = new byte[2];
        in.get(bytes);
        cover.setHight(ByteUtils.byte2Uint16(bytes));
        //打开角度（°）
        bytes = new byte[2];
        in.get(bytes);
        cover.setAngle_1(ByteUtils.byte2Uint16(bytes));
        //打开角度（′）
        bytes = new byte[2];
        in.get(bytes);
        cover.setAngle_2(ByteUtils.byte2Uint16(bytes));
        //电池电量（电压 V*100）
        bytes = new byte[2];
        in.get(bytes);
        cover.setBatterylevel(ByteUtils.byte2Uint16(bytes));
        //电量（%）
        bytes = new byte[1];
        in.get(bytes);
        cover.setElectricity(ByteUtils.BinaryToHexString(bytes));
        //相对湿度（%RH）预留
        bytes = new byte[2];
        in.get(bytes);
        cover.setHumidity(ByteUtils.byte2Uint16(bytes));
        //经度（度分分格式*10000）预留
        bytes = new byte[4];
        in.get(bytes);
        cover.setLongitude(ByteUtils.byte2int(bytes));
        //纬度（度分分格式*10000）预留
        bytes = new byte[4];
        in.get(bytes);
        cover.setLatitude(ByteUtils.byte2int(bytes));
        //预留1
        bytes = new byte[2];
        in.get(bytes);
        cover.setStr1(ByteUtils.BinaryToHexString(bytes));
        //预留2
        bytes = new byte[2];
        in.get(bytes);
        cover.setStr2(ByteUtils.BinaryToHexString(bytes));
        //预留3
        bytes = new byte[4];
        in.get(bytes);
        cover.setStr3(ByteUtils.BinaryToHexString(bytes));

        cover.setAddtime(new Date().getTime());
//        coverDao.save(cover);
        logger.info("cover=" + JSONUtil.beanToJson(cover));
        int dataStatus = updateCover(cover, status);
        logger.info("dataStatus=" + dataStatus);
        cover.setDataStatus(dataStatus);
        coverMapper.insert(cover);
    }

    private int updateCover(Cover cover, String status) {
        Device queryDevice = new Device();
        queryDevice.setEquipmentNum(cover.getDeviceid());
        List<Device> devices = deviceMapper.selectModel(queryDevice);
        int dataStatus = 1;
        if (null != devices) {
            Device device = devices.get(0);
            cover.setLongitude(device.getLongitude());
            cover.setLatitude(device.getLatitude());
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("devicetype", DeviceTypeEnum.JingGai.getCode());
            paramMap.put("kehu_userid", device.getKehuUserid());
            List<Config> configs = configMapper.selectByMap(paramMap);
            device.setDeviceStatus(Integer.valueOf(cover.getDeviceState()));
            device.setDevicetype(Integer.valueOf(DeviceTypeEnum.JingGai.getCode()));
            Integer angle_2 = 0;
            boolean isEques = false;
            logger.info("========================比对数据状态"+ configs.size());
            for (Config config : configs) {
                if (config.getName().equals("temperature") && StringUtil.isNotBlank(config.getValue())) {
                    if (cover.getTemperature() > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                } else if (config.getName().equals("jinggaihight") && StringUtil.isNotBlank(config.getValue())) {
                    if (cover.getHight() > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                } else if (config.getName().equals("angle_1") && StringUtil.isNotBlank(config.getValue())) {
                    if (cover.getAngle_1() > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    } else if (cover.getAngle_2().intValue() == Integer.valueOf(config.getValue()).intValue()) {
                        isEques = true;
                    }
                } else if (config.getName().equals("dianliang") && StringUtil.isNotBlank(config.getValue())) {
                    if (cover.getBatterylevel() > Integer.valueOf(config.getValue())) {
                        dataStatus = 2;
                        break;
                    }
                } else if (config.getName().equals("angle_2") && StringUtil.isNotBlank(config.getValue())) {
                    angle_2 = Integer.valueOf(config.getValue());
                }
            }

            if (dataStatus == 1 && isEques) {
                if (cover.getAngle_2() > angle_2) {
                    dataStatus = 2;
                }
            }
            if(status.equals("8") || status.equals("16")){// 移位数据异常
                dataStatus = 2;
            }
            device.setDataStatus(dataStatus);
            deviceService.update(device);
        }
        return dataStatus;
    }

    public static void main(String[] args) {
//        String str = "3F3F62000100010000000000000000000000000000000000000000000000000000000041CB000000001F9308CA023205460778000000000000000000040400937F3C4309E71CFE81BFD06EAA0201000000000000000000000046057807320201E9090000CA08830D4040";
//
////        String str = "3F 3F 7A 00 01 00 02 01 00 38 39 38 36 30 37 42 39 31 39 31 37 37 30 31 37 33 30 36 37 38 36 36 32 39 37 30 33 36 39 36 30 36 36 39 30 30 30 30 30 30 30 30 33 33 33 30 33 38 33 32 33 33 33 37 34 37 30 39 33 31 30 30 36 34 30 30 55 01 01 00 12 03 1B 0B 0A 00 d0 09 ca 08 ca 08 46 05 78 07 32 02 01 88 13 4D 01 5F AC 0D B2 00 15 00 F0 16 ED 06 C8 F9 54 02 00 00 00 00 00 00 00 00 0E 19 40 40";
//        ByteArrayDecoder rd = new ByteArrayDecoder();
//        IoBuffer ioBuffer = stringToIoBuffer(str);
//        rd.decoding(ioBuffer);
//        rd.decoding(str);
    }

    public static IoBuffer stringToIoBuffer(String str) {
        byte bt[] = str.getBytes();
        IoBuffer ioBuffer = IoBuffer.allocate(bt.length);
        ioBuffer.put(bt, 0, bt.length);
        ioBuffer.flip();
        return ioBuffer;
    }
}
